

#include "Debug.h"
#include "BSP_Sleep.h"
#include "Modules/BLE/BLE.h"
#include <HID/command.h>
#include <HID/HIDiClass.h>
#include <HID/SIM.h>
#include <HID/HIDBLE.h>

#include "serialization/asn1.h"
#include "serialization/t1.h"
#include "router/router.h"

#define BLE_STATE_CONNECTED		0x01
#define BLE_STATE_NOTIFY_EN		0x02
#define BLE_STATE_HANDLE_VALID		0x04
#define BLE_STATE_READY				0x08

#define BLE_STATE_OK	\
	(BLE_STATE_CONNECTED|BLE_STATE_NOTIFY_EN|BLE_STATE_HANDLE_VALID)

#define EOT_STATUS_OK		0x01
#define EOT_STATUS_REJECT	0x02

typedef enum {
    STATE_MOBILE_NOT_FOUND,
    STATE_MOBILE_CONNECTED,
    STATE_MOBILE_SUBSCRIBED,
    STATE_SETDETECTEDCARDINFO,
    STATE_WAIT_FOR_NOTIFY_ENABLE,
    STATE_GETCONTENTELEMENT2,
    STATE_MOBILE_DISCONNECTED,
    STATE_DISCONNECT,
    STATE_TERMINATE_CONNECTION,
    STATE_WAIT_FOR_PACS,
    STATE_PACS_RECEIVED,
    TOTAL_STATES
} app_state_t;

int Reader_HID_HF_ExtractData(uint8_t * ptr, uint16_t objectLength, uint8_t tag, uint8_t* pdata, uint8_t* dlen);

/*============================================================================================*/
typedef struct {
	t1_inf_t inf;
    uint16_t length;
	uint8_t payload[512];
}router_frame_t;

int router_queue_push(uint8_t src, uint8_t dest, uint8_t reply, void* payload, uint16_t length);

void router_frame_reset(router_frame_t* frame){
	memset(&frame->inf, 0, sizeof(t1_inf_t));
	memset(frame->payload, 0, sizeof(frame->payload));
	frame->length = 0;
	frame->inf.payload = frame->payload;
}


static router_frame_t router_frame;
static uint8_t inf_buffer[512];

int router_queue_push(uint8_t src, uint8_t dest, uint8_t reply, void* payload, uint16_t length){
	router_frame_reset(&router_frame);
	t1_inf_t* inf = &router_frame.inf;
	inf->header.source = src;
	inf->header.destination = dest;
	inf->header.reply = reply;
	memcpy(inf->payload, payload, length);
	router_frame.length = length;
	return 0;
}

int router_queue_push_inf(t1_inf_t* inf, uint16_t len){
	const payload_header_t* h = &inf->header;
	return router_queue_push(h->source, h->destination, h->reply, inf->payload, len);
}

static int ext_app_proc(uint8_t wdt, t1_inf_t* cmd, uint16_t clen, t1_inf_t* resp, uint16_t* rlen){
	int ret = -1;
	uint32_t cnt = 0;
	t1_inf_t* inf;
	uint16_t len;
	
	router_queue_push_inf(cmd, clen);
	while(cnt < 100){
		cnt++;
		inf = &router_frame.inf;
		len = router_frame.length;
		if(inf->header.destination == NODE_EXT_APP){
			resp->header = inf->header;
			memcpy(resp->payload, inf->payload, len);
			*rlen = len;
			return 0;
		}
		ret = router_route(inf, len);
		if(ret){
			return ret;
		}
	}
	LOG_E("Loop terminal!!");
	return -1;
}
/*============================================================================================*/

int rhb_set_detected_card_info(void) {
	LOG_W("set_detected_card_info");
    asn1_builder_t build_set_detected_card_info;
    ASN1(build_set_detected_card_info, ->TAG(SAMCOMMAND)
                                     ->TAG(SAMCOMMAND_SET_DETECTED_CARD_INFO)
                                     ->TAG(DETECTED_CARD_INFO)
                                     ->TAG(PROTOCOL)
                                     ->VALUE(PROTOCOL_APDU_OVER_BLE)
                                     ->CLOSE()
                                     ->TAG(CSN)
                                     ->VALUE({0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF})
                                     ->CLOSEALL());

    t1_inf_t inf = {.header = {.destination = NODE_SAM,
                               .source = NODE_EXT_APP,
                               .reply = NODE_EXT_APP,
                               .secure_channel = 0,
                               .RFU1 = 0,
                               .RFU2 = 0},
                    .payload = build_set_detected_card_info.payload};
	t1_inf_t r_inf = {.payload = inf_buffer,};
	uint16_t rlen = 0;
	int ret = ext_app_proc(0, &inf, build_set_detected_card_info.dataPtr, &r_inf, &rlen);
	if(ret){
		LOG_E("error: %d", ret);
	}
	else{
		LOG_B("ok", r_inf.payload, rlen, 16);
	}
	return ret;
}

int rhb_get_content_element_2(uint8_t* pacs, uint8_t* len) {
	LOG_W("get_content_element_2");
    asn1_builder_t build_get_content_element2;
    ASN1(build_get_content_element2, ->TAG(SAMCOMMAND)
                                   ->TAG(SAMCOMMAND_GET_CONTENT_ELEMENT2)
                                   ->TAG(CONTENT_ELEMENT_TAG)
                                   ->VALUE(IMPLICIT_FORMAT_PHYSICAL_ACCESS_BITS)
                                   ->CLOSE()
                                   ->TAG(EXIT_RF_ACTION)
                                   ->VALUE(EXIT_RF_ACTION_NONE)
                                   ->CLOSEALL());

    t1_inf_t inf = {.header = {.destination = NODE_SAM,
                               .source = NODE_EXT_APP,
                               .reply = NODE_EXT_APP,
                               .secure_channel = 0,
                               .RFU1 = 0,
                               .RFU2 = 0},
                    .payload = build_get_content_element2.payload};

	t1_inf_t r_inf = {.payload = inf_buffer,};
	uint16_t rlen = 0;
	uint8_t status;
	int ret = ext_app_proc(0, &inf, build_get_content_element2.dataPtr, &r_inf, &rlen);
	if(ret){
		LOG_E("error: %d", ret);
	}
	else{
		LOG_B("resp", r_inf.payload, rlen, 16);
		const uint8_t tag = 0x80;
		ret = Reader_HID_HF_ExtractData(r_inf.payload, rlen, tag, pacs, len);
		if(ret){
			status = EOT_STATUS_REJECT;
		}
		else{
			status = EOT_STATUS_OK;
		}
		LOG_I("EOT: %02X", status);
		hid_ble_eot(status, 100);
	}
	
	return ret;

}

static int rhb_check_state(void){
	LOG_W("reader hid ble check state");
	uint8_t states[3] = {0};

	int ret = hid_ble_get_state(states, 100);
	if(ret){
		return -1;
	}
	
	if(states[0] != 2){
		//非HID广播
		return -2;
	}

	if(states[2] != STATE_WAIT_FOR_PACS){
		//不处于PACS状态
		return -3;
	}
	
	if((states[1] & BLE_STATE_OK) != BLE_STATE_OK){
		//连接未准备好
		return -3;
	}
	//连接OK，可以启动PACS流程
	return 0;
}

int rhb_get_pacs(uint8_t* pacs, uint8_t* len){
	int ret;
	uint8_t atr[32];
	uint8_t alen;
	ret = rhb_check_state();
	if(ret){
		return 1;
	}
	ret = SIM_PowerOn(atr, &alen);
	if(ret){
		LOG_E("SIM_PowerOn fail: %d", ret);
		return -1;
	}
	ret = rhb_set_detected_card_info();
	if(ret){
		LOG_E("rhb_set_detected_card_info fail: %d", ret);
		return -3;
	}
	ret = rhb_get_content_element_2(pacs, len);
	if(ret){
		LOG_E("rhb_get_content_element_2 fail: %d", ret);
		return -4;
	}
	LOG_B("pacs", pacs, *len, 16);
	return ret;
}

static int rhb_get_mac(uint8_t* mac, uint8_t* mlen){
	uint8_t code = 1;
	uint16_t rlen = 0;
	uint8_t resp[16];
	BLE_Send_Frame(BLE_Cmd_GetMac, NULL, 0);
	int ret = BLE_Receive_Frame(&code, resp, &rlen, 100);
	if(ret){
		return ret;
	}
	if(code){
		return -1;
	}
	//获取远端mac
	memcpy(mac, &resp[6], 6);
	*mlen = 6;
	return 0;
}

int rhb_poll(uint8_t* mac, uint8_t* mlen){
	int ret = rhb_check_state();
	if(ret){
		return -1;
	}
	return rhb_get_mac(mac, mlen);
}


